home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
Games
/
ms-0.07
/
mslaved
/
mslavedc.c
< prev
Wrap
C/C++ Source or Header
|
1995-06-26
|
7KB
|
298 lines
/* mslavedc.c - MandelSpawn computation server control program */
/* (named in accordance with timedc, etc.). */
/*
This file is part of MandelSpawn, a network Mandelbrot program.
Copyright (C) 1990-1993 Andreas Gustafsson
MandelSpawn is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 1,
as published by the Free Software Foundation.
MandelSpawn is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License,
version 1, along with this program; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
/*
The only system I know needs the following two #includes is SCO Unix,
which needs them to define FNDELAY. If they cause trouble with your
system, just remove them.
*/
#include <sys/types.h>
#include <sys/file.h>
/* This is for Linux */
#ifndef FNDELAY
#ifdef O_NDELAY
#define FNDELAY O_NDELAY
#endif
#endif
#include "datarep.h"
#include "ms_ipc.h"
#define RETRIES 5 /* how many times to retry getting a PID in ping() */
extern int errno; /* 4.3BSD needs this even when errno.h is included */
char *me; /* name of program */
int port = DEFAULT_PORT; /* UDP port */
char *command = NULL;
int kill_mode = 0;
int timeout_supplied = 0; /* true if user gave a timeout option */
/* Report a fatal error and exit */
void error(s)
char *s;
{ fprintf(stderr, "%s: ", me);
perror(s);
exit(1);
}
/*
Repeatedly send datagrams to "host" trying to find out the pid of
an existing server, if any. Returns the pid, or 0 if no response.
*/
int ping(host)
char *host;
{ int i;
int status;
WhoAreYouMessage out;
Message in;
int osock, isock;
struct sockaddr_in oname, iname, mname;
int mnamelen;
struct hostent *hp, *gethostbyname();
/* set up the output socket; use an arbitrary port */
osock=socket(AF_INET, SOCK_DGRAM, 0);
if(osock<0)
{ error("opening output socket");
}
hp=gethostbyname(host);
if(hp==0)
{ error("unknown host");
}
/* set up the destination address */
oname.sin_family=AF_INET;
oname.sin_port=htons(port);
bcopy(hp->h_addr, (char *)&oname.sin_addr, hp->h_length);
isock=socket(AF_INET, SOCK_DGRAM, 0);
if(isock<0)
{ error("opening input socket");
}
iname.sin_family=AF_INET;
iname.sin_addr.s_addr=INADDR_ANY;
iname.sin_port=0;
if(bind(isock, &iname, (int) sizeof(iname)))
{ error("binding input socket");
}
if(fcntl(isock, F_SETFL, FNDELAY) == -1)
{ error("unblocking socket");
}
mnamelen=sizeof(mname);
if(getsockname(isock, &mname, &mnamelen)== -1)
error("getsockname");
out.header.magic=htons(MAGIC);
out.header.version=htons(VERSION);
out.header.type=htons(WHO_R_U_MESSAGE);
out.port=mname.sin_port; /* in network byte order already */
for(i=0; i<RETRIES; i++)
{ int nbytes;
int fromlen;
if(sendto(osock, (char *)&out, sizeof(WhoAreYouMessage), 0,
(struct sockaddr *)&oname, sizeof(oname)) < 0)
error("sending pid inquiry message");
/*
This previously used read(), but some non-BSD TCP/IP implementations
don't allow it to be used with connectionless sockets. Also,
while the Sun implementation does allow for a null pointer
for the "from" argument in recvfrom(), the "fromlen" argument
may not be a null pointer.
*/
nbytes = recvfrom(isock, (char *) &in, sizeof(in),
0, (struct sockaddr *) 0, &fromlen);
if(nbytes == 0
#ifdef EWOULDBLOCK
|| (nbytes == -1 && errno == EWOULDBLOCK)
#endif
)
{ /* no reply yet */
sleep(1);
}
else if(nbytes == -1)
{ error("receiving pid info");
}
else /* got a reply */
{ status=ntohs(in.iam.pid);
goto done;
}
}
status=0; /* unsuccessful */
done:
(void) close(osock);
(void) close(isock);
return(status);
}
/*
Kill any server that is already active in this machine.
Return 0 if successful kill, 1 if no response.
*/
int murder()
{ int pid;
char my_name[256];
if(gethostname(my_name, sizeof(my_name)) == 1)
error("gethostname");
pid=ping(my_name); /* get pid of existing server, if any */
if(pid==0)
return(1); /* return failed exit status */
if(kill(pid, SIGTERM)== -1)
error("kill");
return(0);
}
/* argument list for mslaved */
static char *arglist[16]; /* more than enough */
static char **arglistp = arglist+1; /* pointer to the above */
void copy_arg(p)
char *p;
{ *arglistp++ = p;
}
/* Set up the file handles and exec an mslaved */
void birth()
{ int isock;
struct sockaddr_in iname;
int tty;
int i;
/* set up the socket */
isock=socket(AF_INET, SOCK_DGRAM, 0);
if(isock<0)
{ error("opening socket");
}
iname.sin_family=AF_INET;
iname.sin_addr.s_addr=INADDR_ANY;
iname.sin_port=htons(port);
if(bind(isock, &iname, (int) sizeof(iname)) == -1)
{ /* probable cause of error is that the port is in use */
error("binding socket");
}
/* dup the newly-opened socket to stdin */
close(0);
dup(isock);
#ifdef TIOCNOTTY /* presumably BSD-like */
if((tty=open("/dev/tty", 0, 0)) != -1)
{ ioctl(tty, TIOCNOTTY, (struct sgttyb *) 0);
(void) close(tty);
}
else
{ if(setpgrp(0, 0))
error("setpgrp");
}
#else /* presumably SYSV-like */
setpgrp();
#endif
for(i=1; i<10; i++)
(void) close(i);
arglist[0] = command;
/* supply a default timeout if none was given */
if(!timeout_supplied)
copy_arg("-t900");
copy_arg((char *) 0);
execvp(command, arglist);
exit(1); /* there's no good way to report errors here */
}
int main(argc, argv)
int argc; char **argv;
{ char *s;
me=argv[0];
for(;s = *++argv, --argc;)
{ if(*s != '-')
{ command = s;
}
else
{ switch(s[1])
{
case 'k': /* kill */
kill_mode++;
break;
case 'q': /* query */
{ int rpid = ping(s[2] ? s+2 : (--argc, *++argv));
if(rpid)
{ printf("%d\n", rpid);
exit(0);
}
else
exit(1);
}
case 't': /* timeout */
timeout_supplied = 1;
/* fallthrough */
case 'n': /* nice */
/* copy these options and possible separate option arguments to */
/* the mslaved argument list */
copy_arg(s);
if(! s[2])
copy_arg((--argc, *++argv));
break;
case 'p': /* port */
port = atoi(s[2] ? s+2 : (--argc, *++argv));
break;
default:
goto usage;
}
}
}
if(kill_mode)
exit(murder());
if(!command)
error("missing command");
switch(fork())
{ case -1:
error("fork");
case 0: /* child */
birth();
default: /* parent */
exit(0);
}
usage:
fprintf(stderr, "usage: %s [-k] [-q] [-nnice] [-ttimeout] [-pport]\n", me);
exit(1);
}